package com.chen;



import com.chen.openapiclientsdk.utils.SignUtils;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.*;

@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    //白名单
    private static final ArrayList<String> whiteList = new ArrayList<>(Arrays.asList("127.0.0.1"));
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //请求日志
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        ServerHttpRequest request = exchange.getRequest();
        log.info("request uri:{}",request.getURI());
        log.info("request method:{}",request.getMethod());
        log.info("request path:{}",request.getPath());
        log.info("request 参数:{}",request.getQueryParams());
        //请求地址
        String host = null;
        log.info("request host:{}", host = Objects.requireNonNull(request.getRemoteAddress()).getHostName());
        //......
        if(!whiteList.contains(host)){
            //鉴权失败
            log.info("鉴权失败");
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();//返回momo值
        }

        //用户鉴权  对nonce和timestamp的校验 以及对accesskey 和 scretkey的校验 mapper操作
        HttpHeaders headers = request.getHeaders();
        String body = headers.getFirst("body");
        String sign = headers.getFirst("sign");
        String nonce = headers.getFirst("nonce");
        String timestamp = headers.getFirst("timestamp");
        //TODO 去数据库中查（common）
        String accessKey = headers.getFirst("accessKey");

        Map<String, String> keyMap = new HashMap<>();
        keyMap.put("accessKey", accessKey);
        keyMap.put("nonce",nonce);
        keyMap.put("body", body);
        keyMap.put("timestamp",timestamp);
        //TODO scretkey从数据库中查（common）
        String abcdefg = SignUtils.genSign(keyMap, "abcdefg");
        assert sign != null;
        if (!sign.equals(abcdefg)){
            log.info("鉴权失败");
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();//返回momo值
        }
        //模拟接口是否存在
        URI uri = request.getURI();
        //TODO mapper层操作怎么做？maven第三方包创建service
        //请求转发调用用模拟接口 restTempalte 根据http状态值查看是否成功
        //响应日志
        //时调用成功，次数加+1 之前项目的impl层有这个方法ServiceImpl<UserInterfaceInfoMapper   mapper操作
        //调用失败返回一个错误码

        try {
            ServerHttpResponse originalResponse = exchange.getResponse();
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
            HttpStatus statusCode = originalResponse.getStatusCode();
            if (statusCode != HttpStatus.OK) {
                return chain.filter(exchange);//降级处理返回数据
            }
            //装饰器的真正实现。
            ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (body instanceof Flux) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);

                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {

                            // 合并多个流集合，解决返回体分段传输
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer buff = dataBufferFactory.join(dataBuffers);
                            byte[] content = new byte[buff.readableByteCount()];
                            buff.read(content);
                            DataBufferUtils.release(buff);//释放掉内存

                            // 构建返回日志
                            String joinData = new String(content);
                            //响应已经成功
                            //TODO 调用次数加1 invoke方法。

                            List<Object> rspArgs = new ArrayList<>();//TODO 可以删除 这个其实就是响应日志 mapper
                            rspArgs.add(originalResponse.getStatusCode().value());
                            rspArgs.add(exchange.getRequest().getURI());
                            rspArgs.add(joinData);

                            getDelegate().getHeaders().setContentLength(joinData.getBytes().length);
                            return bufferFactory.wrap(joinData.getBytes());
                        }));
                    } else {
                        log.error("<-- {} 响应code异常", getStatusCode());
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(decoratedResponse).build());

        } catch (Exception e) {
            log.error("网关处理异常请求\n" + e);
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        return -1;
    }
}